package main

import (
	"fmt"
)

/*
函数介绍

	Go语言的【函数本身】可以作为值进行传递，既支持匿名函数和闭包，又能满足接口，所以Go语言的函数属于一等公民。参数、变量和返回值都可以是函数。
	作为一等公民，函数还能实现接口
*/
func main() {

	/*
		一. 函数格式：func 函数名（参数列表）(返回值列表) { // 函数体 }

			TIPS：
				· 在参数列表中，如果有多个参数变量，则以逗号分隔；如果【相邻变量是同类型】，则可以将类型省略；
				· 如果参数的类型全部相同，且这个函数可以接受不定数量的参数，可以使用 arg ...参数类型的格式接受。
				   一个函数【最多只能有一个可变参数，若参数列表中还有其他类型参数，则可变参数写在所有参数的最后】，
				   变量是一个指定参数类型的slice（切片）；
				· Go语言的函数可以返回多个值。返回值可以是返回数据的数据类型，也可以是变量名+变量类型的组合；
				· 如果只有一个返回值并且没有声明返回值变量，那么可以省略包括返回值的括号；
				· 如果函数没有声明返回值，函数中也可以使用return关键字，用于强制结束函数
	*/
	a := 10
	b := 20
	c, d := crossoverValue(a, b)
	fmt.Println("交换后的值", c, d)
	condition := 5
	argValue(condition, 1, 2, 3, 4, 5, 6, 7, 11)

	/*
		二. 变量作用域
			1. 在函数体内声明的变量称为局部变量，它们的作用域只在函数体内，生命周期同所在的函数。参数和返回值变量也是局部变量；
			2. 在函数体外声明的变量称为全局变量，全局变量可以在整个包甚至外部包（被导出后）使用。全局变量的生命周期同 main() 函数；
			3. 全局变量可以在任何函数中使用。Go语言程序中全局变量与局部变量名称可以相同，但是函数内的局部变量会被优先考虑
	*/

	/*
		三. 内置函数。Go 语言拥有一些不需要进行导入操作就可以使用的内置函数
				append          	-- 用来追加元素到数组、slice中，返回修改后的数组、slice
				close           	-- 主要用来关闭channel
				delete            	-- 从map中删除key对应的value
				panic            	-- 停止常规的goroutine（panic和recover：用来做错误处理）
				recover         	-- 允许程序定义goroutine的panic动作
				imag            	-- 返回complex的实部（complex、real imag：用于创建和操作复数）
				real            	-- 返回complex的虚部
				make            	-- 用来分配内存，返回Type本身(只能应用于slice, map, channel)
				new                	-- 用来分配内存，主要用来分配值类型，比如int、struct。返回指向Type的指针
				cap                	-- capacity是容量的意思，用于返回某个类型的最大容量（只能用于切片和 map）
				copy           		-- 用于复制和连接slice，返回复制的数目
				len                	-- 来求长度，比如string、array、slice、map、channel ，返回长度
				print、println     	-- 底层打印函数，在部署环境中建议使用 fmt 包
	*/
}

/*
交换两个整数值

TIPS：

	① 可以不用指定返回值的名称。例如下面可以写作：func crossoverValue(a int, b int) (int, int) { // 函数体} ；
	② 函数的参数中如果【相邻变量】的类型相同，则可以省略类型：func crossoverValue(a, b int) (int, int) { // 函数体}；
	③ 函数的多返回值如果【相邻变量】的类型相同，则可以省略类型：func crossoverValue(a, b int)(c, d int) { // 函数体}；
	④ 如果只有一个返回值并且没有声明返回值变量，那么可以省略包括返回值的括号；
*/
func crossoverValue(a int, b int) (c, d int) {

	a, b = b, a
	// 返回多个值
	return a, b
}

/*
不定参数个数函数（可变参数列表）： arg ...参数类型 的参数格式

TIPS：

	① 本质上，函数的可变参数是通过切片来实现的；
	② 可变参数通常要作为函数的最后一个参数；
*/
var e = 3

func argValue(condition int, arg ...int) {

	for index, value := range arg {
		// 如果函数没有声明返回值，函数中也可以使用return关键字
		if value > condition {
			return
		}
		fmt.Println("arg ...参数类型 的参数格式", index, value)
	}
}
